﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ContactManagement.Models;
using EFDataModel;
using Common.Extensions;

namespace ContactManagement.AppCode.CategoryManagement
{
    public class WebUserRights : CategoryBase
    {
        #region Static
        /// <summary>
        /// Singleton Pattern für die aktuellen UserRights
        /// </summary>
        /// <param name="controller">Der Aktuelle Controller</param>
        /// <returns>Instanz der aktuellen WebUserRights</returns>
        public static WebUserRights UserRights(Controller controller)
        {
            return new WebUserRights(controller);
        }
        #endregion

        #region Member
        /// <summary>
        /// Der Aktuelle Controller, damit auch auf die Tempdaten und alles notwendige zugegriffen werden kann
        /// </summary>
        protected override sealed Controller CurrentController { get; set; }
        #endregion

        #region Konstruktor
        /// <summary>
        /// Initialisieren der WebUserRights
        /// </summary>
        /// <param name="controller">der Aktuelle Controller</param>
        public WebUserRights(Controller controller)
        {
            CurrentController = controller;
        }
        #endregion

        #region Public Functions
        /// <summary>
        /// Sucht alle Rechte für den übergenenen User heraus, die ihm zugewiesen sind bzw. nicht zugewiesen sind.
        /// Dabei werden nur die Rechte die dem Nutzer selbst zugewiesen wurden beachtet. Es gibt eine Dritte Liste 
        /// in der Sind alle Vererbten Userrights angegeben inkl. der Gruppen wo diese gesetzt sind.
        /// </summary>
        /// <param name="userId">Die UserId für die die Rechte angezeigt werden.</param>
        /// <returns>passende UserRightsModel</returns>
        public UserRightListModel UserRightsByUserId(int userId)
        {
            //Laden des Users dessen Rechte angezeigt werden sollen
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);

            //Initialisieren des Models und der Listen
            UserRightListModel userRightListModel = new UserRightListModel();
            List<UserRight> hasNoUserRight = new List<UserRight>();
            userRightListModel.InheritUserRightsFromGroups = new SortedList<UserRight, List<UserGroup>>();
            
            //Den User zuweisen der angezeigt werden soll
            userRightListModel.CurrentUser = efUser;
            //Zuweisen der Rechte die der User hat.
            userRightListModel.HasUserRight = efUser.UserRights.OrderByUrlParams();

            //Alle Rechte durchgehen und prüfen welche Rechte dem User noch nicht zugeteilt wurden und diese dann dem Model hinzufügen
            var allUserRights = from eUserRight in CurrentHttpContext.GetDataModel().EFCategoryMenge.OfType<UserRight>() select eUserRight;
            foreach (UserRight eUserRight in allUserRights)
            {
                //Wenn dem User das Recht noch nicht direkt zugeordnet wurde, dann in der Liste mit den Nicht zugeordneten Rechten hinzufügen
                if (!efUser.UserRights.Contains(eUserRight))
                {
                    hasNoUserRight.Add(eUserRight);
                }
            }

            //Die Liste zuordnen und Sortieren
            userRightListModel.HasNoUserRight = hasNoUserRight.OrderByUrlParams();

            //Noch prüfen aus welchen Gruppenzuordnungen der User welche Rechte erbt.
            foreach (UserGroup eUserGroup in efUser.UserGroups)
            {
                foreach (UserRight eUserRight in eUserGroup.UserRights)
                {
                    //Wenn das UserRight noch nicht in der Liste enthalten ist, dann hinzufügen
                    UserRight right = eUserRight;
                    //if (userRightListModel.InheritUserRightsFromGroups.Where(p=>p.Key.TypeId == right.TypeId).Count() == 0)
                    if (!userRightListModel.InheritUserRightsFromGroups.ContainsKey(right))
                    {
                        userRightListModel.InheritUserRightsFromGroups.Add(right, new List<UserGroup>());
                    }

                    //Hinzufügen der jeweiligen UserGruppe zum UserRight, wenn diese noch nicht der Gruppenauflistung hinzugefügt wurde.
                    if (!userRightListModel.InheritUserRightsFromGroups[right].Contains(eUserGroup))
                    {
                        userRightListModel.InheritUserRightsFromGroups[right].Add(eUserGroup);
                    }
                }
            }

            return userRightListModel;
        }

        /// <summary>
        /// Herraussuchen welche User das Recht haben und welche User das Recht nicht haben
        /// Achtung es muss auch in den Rechte für die UserGroups geschaut werden, ob der User da mitglied ist und das Recht hat.
        /// </summary>
        /// <param name="userRightId">das Userrecht nach dem gesucht werden soll</param>
        /// <returns>das passende Model | Null bei einem Fehler</returns>
        public UserRightUsersListModel UserRightsByUserRightId(int userRightId)
        {
            try
            {
                //Initialisieren des Models
                UserRightUsersListModel userGroupUsersListModel = new UserRightUsersListModel();
                //Als erstes alle User heraussuchen die in der Usergroups selbst enthalten sind, es fehlen dann noch die User die in einer Gruppe sind die die Rechte hat.
                UserRight userRight = (UserRight) CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userRightId);
                userGroupUsersListModel.CurrentRight = userRight;

                //Aus der UserGruppe die Gruppen heraussuchen bei denen das Recht ebenfalls gesetzt ist und die User dieser Gruppe gehören dann ebenfalls zu der Liste UsersInGroup.
                var efUsersInGroupTmp = from eUserGroup in userRight.UserGroups where eUserGroup.UserRights.Where(p => p.ID == userRightId).Count() != 0 select eUserGroup.EFUsers;

                List<EFUser> efUsersInGroup = userRight.EFUsers.ToList();
                //Die Auflistung mit der Userauflistung für jede Gruppe durchgehen und dann die Nutzer noch der Hauptliste hinzufügen
                foreach (EntityCollection<EFUser> efUsers in efUsersInGroupTmp)
                {
                    foreach (EFUser efUser in efUsers)
                    {
                        if (!efUsersInGroup.Contains(efUser))
                        {
                            efUsersInGroup.Add(efUser);
                        }
                    }
                }

                //Die komplette Liste der Nutzer die das Recht haben setzten.
                userGroupUsersListModel.UsersInGroup = efUsersInGroup.OrderByUrlParams();

                //Erstellen der Liste der User die nicht das Recht besitzen, dazu werden einfach alle User durchgegangen und mit der Liste abgeglichen
                var allUsers = from efUser in CurrentHttpContext.GetDataModel().EFBaseMenge.OfType<EFUser>() select efUser;
                List<EFUser> efUsersNotInGroup = new List<EFUser>();
                //Alle User des System durchgehen
                foreach (EFUser efUser in allUsers)
                {
                    //Wenn der User nicht in der Liste der User ist die das Recht besitzen, dann in die Liste der User aufnehmen die das Recht nicht besitzen.
                    if (!efUsersInGroup.Contains(efUser))
                    {
                        efUsersNotInGroup.Add(efUser);
                    }
                }

                //Dem Model die Liste hinzufügen.
                userGroupUsersListModel.UsersNotInGroup = efUsersNotInGroup.OrderByUrlParams();

                return userGroupUsersListModel;
            }
            catch (Exception)
            {
                //Ein unvorhergesehener Fehler ist aufgetreten bitte erneut versuchen.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.ErrorPleaseTryAgainRESX,MessageTypes.error);
            }
            
            return null;
        }

        /// <summary>
        /// Benutzer dem das Recht hinzugefügt werden soll.
        /// </summary>
        /// <param name="userId">User Id der das Recht hinzugefügt werden soll</param>
        /// <param name="userRightDbId">Die RechteDb Id die dem User hinzugefügt werden soll</param>
        /// <returns>TRUE->Erfolgreich hinzugefügt | FALSE->Fehler beim Hinzufügen</returns>
        public bool AddUserRightToUser(int userId, int userRightDbId)
        {
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            UserRight userRight = (UserRight) CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userRightDbId);

            //Prüfen ob der User bereits das Recht enthält, hier werden keine weiteren UserGruppen überprüft hier 
            //werden nur die Rechte geprüft die direkt am User hängen.
            if (!efUser.UserRights.Contains(userRight))
            {
                //Den User der Gruppe hinzufügen
                efUser.UserRights.Add(userRight);
                CurrentHttpContext.GetDataModel().SaveChanges();
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightAddedSuccessfullyToListRESX, MessageTypes.ok);
                return true;
            }
            else
            {
                //Der Benutzer besitzt das Recht bereits
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserAllreadyInRightGroupRESX,MessageTypes.warning);
            }

            return false;
        }

        /// <summary>
        /// Benutzer dem ein Recht entfernt werden soll. Das Recht kann nur entfernt werden wenn dies nur dem User hinzugefügt wurde.
        /// Wenn das Recht auch einer Gruppe hinzugefügt wurde die der User angehört, dann kann das Recht nicht komplett entfernt werden.
        /// </summary>
        /// <param name="userId">UserId der das Recht entzogen werden soll</param>
        /// <param name="userRightDbId">UserRightDb Id die dem User entzogen werden soll</param>
        /// <returns>TRUE->Erfolgreich | FALSE->Fehler beim Entfernen</returns>
        public bool DeleteUserRightFromUser(int userId, int userRightDbId)
        {
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            UserRight userRight = (UserRight)CurrentHttpContext.GetDataModel().EFCategoryMenge.Find(userRightDbId);

            //Bevor das Recht entfernt werden kann erst prüfen ob der User in einer Gruppe ist die das Recht enthält.
            int isRightInGroup = (from eUserGroup in efUser.UserGroups where eUserGroup.UserRights.Where(p => p.ID == userRightDbId).Count() != 0 select eUserGroup.ID).Count();
            
            //erst prüfen ob der User überhaupt das Recht hat, das Recht kann auch in einer Gruppe enthalten sein die dem User zugeorndet ist.
            if (efUser.UserRights.Contains(userRight))
            {
                efUser.UserRights.Remove(userRight);
                CurrentHttpContext.GetDataModel().SaveChanges();
                //Wenn keine Gruppen gefunden werden konnte der das Recht zugeordnet ist, dann hat der User das Recht nicht mehr
                if (isRightInGroup == 0)
                {
                    //Erfolgreich das Recht entfernt.
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightDeletedSuccessfullyFromListRESX, MessageTypes.ok);
                    return true;
                }
                else
                {
                    //Das Recht hat noch eine ihm zugewiesene Gruppe
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightDeletedSuccessfullyFromListButNotFromGroupsRESX, MessageTypes.warning);
                }
            }
            else
            {
                //Das UserRight ist nicht mehr im User selbst, aber in einer Gruppe gesetzt die dem User zugewiesen ist.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserRightIsSetInUserGroupsRESX, MessageTypes.warning);
            }

            return false;
        }

        /// <summary>
        /// Den User von allen Gruppen entfernen die dieses Recht besitzen.
        /// </summary>
        /// <param name="userId">UserId der das Recht entfernt werden soll</param>
        /// <param name="rightId">Die RechteId die dem User entfernt werden soll</param>
        /// <returns>TRUE->Das Recht konnte erfolgreich entfernt werden | FALSE->Fehler beim Entfernen des passenden Rechts.</returns>
        public bool DeleteGroupRightsFromUser(int userId, int rightId)
        {
            //Den User aus der DB abrufen.
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);

            //Alle Gruppen heraussuchen in denen der Usern Mitglied ist und das passende Right gesetzt ist.
            var groups = from eUserGroup in efUser.UserGroups where eUserGroup.UserRights.Where(p => p.ID == rightId).Any() select eUserGroup.ID;
            bool isRemoved = true;

            //WebUserGroups Objekt erstellen, damit kann am einfachsten der User aus der jeweiligen Gruppe entfernt werden.
            WebUserGroups webUserGroups = new WebUserGroups(CurrentController);

            foreach (int eGroupId in groups.ToList())
            {
                //Entfernen der jeweiligen Gruppe vom User, das Speichern wird bereits in der Funktion erledigt.
                if (!webUserGroups.DeleteUserFromGroup(eGroupId, userId))
                {
                    //Nur bei einem Fehler beim Entfernen des Users Aus der Gruppe isRemoved auf False setzten.
                    isRemoved = false;
                }
            }

            if (isRemoved)
            {
                //Alles erfolgreich gelaufen, die passendne Gruppen die die Rechte vererbt haben wurden entfernt.
                CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserGroupRightsRemovedFromUserRESX,MessageTypes.ok);
                return true;
            }

            //es ist ein Fehler aufgetreten beim Entfernen der Rechte.
            CustomMessage.CurrentMessage(CurrentController).AddMessage(App_GlobalResources.SystemMessages.UserGroupRightsRemovedFromUserErrorRESX, MessageTypes.error);
            return false;
        }
        #endregion

        #region Not in Use
        public override bool Add(CategoriesAddModel model)
        {
            throw new NotImplementedException();
        }

        public override bool Delete(int id)
        {
            throw new NotImplementedException();
        }

        public override CategoriesAddModel Edit(int id)
        {
            throw new NotImplementedException();
        }

        public override bool Edit(int id, CategoriesAddModel model)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}